import SVGArrowDown from '@material-design-icons/svg/filled/keyboard_arrow_down.svg';
import { Input } from '../input/input';
import { PopList, RowType } from '../popList/popList';
import { ColumnOption, getChildren, getText, getValue } from '../list/list';
import { DATA } from '../symbol';
import { PopupHandler } from '../interface';
import { GridConfig } from '../grid/grid';

export interface Select {
	[DATA]: {
		shown: boolean;
		value: unknown;
		data: RowType[];
		opt: ColumnOption;
		gridConfig?: Partial<GridConfig>;
		handler: PopupHandler<Select> | null;
		disableField: number | string | null;
		popupWidth?: number | string;
	};
}

export class Select extends Input {
	constructor() {
		super();
		this[DATA].value = null;
		this[DATA].data = [];
		this[DATA].opt = { text: 'text', value: 'value' };
		this[DATA].handler = null;
		this[DATA].disableField = null;
		super.addClass('select');
		super.suffixIcon(SVGArrowDown);
		this.query('input').attr('readonly', true);
		this.on('click', this.openSelect.bind(this));
		this.on('keyup', (evt) => {
			if (evt.key === 'Space' || evt.key === ' ') {
				this.openSelect();
			}
		});
	}

	config(gridConfig: Partial<GridConfig>) {
		this[DATA].gridConfig = gridConfig;
	}

	private setText(): void {
		const find = (arr: unknown[]): boolean => {
			for (let i = 0; i < arr.length; i++) {
				const row = arr[i];
				if (getValue(row, this[DATA].opt) === this[DATA].value) {
					this.text(getText(row, this[DATA].opt));
					return true;
				} else if (typeof row === 'object' && row !== null) {
					const children = getChildren(row, this[DATA].opt);
					if (children && find(children)) {
						return true;
					}
				}
			}
			return false;
		};
		find(this[DATA].data);
	}

	override clear(): this {
		this.value(null);
		this.text('');
		return this;
	}

	openSelect() {
		if (this.readonly() || this.disabled()) return;
		if (this[DATA].handler) {
			this[DATA].handler
				.bind(this)()
				.then((result) => {
					if (result) {
						const oldValue = this.value();
						this.value(result.value);
						this.text(result.text);
						if (oldValue !== result.value) {
							this.invalid(false);
							this.query('input').emit(new Event('change'));
						}
					}
					this.focus();
				})
				.catch((reason) => {
					console.error(reason);
				});
			return;
		}
		PopList.show(this[DATA].data, this[DATA].opt, {
			refer: this,
			activeValue: this.value(),
			multiSelect: this.multiSelect(),
			useAction: true,
			useSearch: this.filterable(),
			gridConfig: this[DATA].gridConfig,
			focus: true,
			disableField: this[DATA].disableField,
		}).onSelect((value, text) => {
			const oldValue = this.value();
			this.value(value);
			this.text(text + '');
			if (oldValue !== value) {
				this.invalid(false);
				this.query('input').emit(new Event('change'));
			}
		});
	}

	column(): ColumnOption;
	column(opt: ColumnOption): this;
	column(opt?: ColumnOption): this | ColumnOption {
		if (opt === undefined) {
			return this[DATA].opt;
		}
		this[DATA].opt = opt;
		if (this[DATA].opt.text === undefined) {
			this[DATA].opt.text = 'text';
		}
		if (this[DATA].opt.value === undefined) {
			this[DATA].opt.value = 'value';
		}
		this.setText();
		return this;
	}

	multiSelect(): boolean;
	multiSelect(value: boolean): this;
	multiSelect(value?: boolean): this | boolean {
		if (value === undefined) {
			return this.attr('multi-select') != null;
		}
		this.attr('multi-select', value);
		return this;
	}

	filterable(): boolean;
	filterable(value: boolean): this;
	filterable(value?: boolean): this | boolean {
		if (value === undefined) {
			return this.attr('filterable') != null;
		}
		this.attr('filterable', value);
		return this;
	}

	options(): RowType[];
	options(rows: RowType[]): this;
	options(rows?: RowType[]): this | RowType[] {
		if (rows === undefined) {
			return this[DATA].data;
		}
		this[DATA].data = rows;
		this.setText();
		return this;
	}

	/**
	 * Disable some row by field value
	 */
	disableBy(): string | number | null;
	disableBy(value: string | number | null): this;
	disableBy(value?: string | number | null): string | number | null | this {
		if (value === undefined) {
			return this[DATA].disableField;
		} else {
			this[DATA].disableField = value;
			return this;
		}
	}

	popupWidth(value: string | number): this {
		this[DATA].popupWidth = value;
		return this;
	}

	override value(): unknown;
	override value(val: unknown): this;
	override value(val?: unknown): this | unknown {
		if (val === undefined) {
			return this[DATA].value;
		}
		this[DATA].value = val;
		this.setText();
		return this;
	}

	override readonly(): boolean;
	override readonly(value: boolean): this;
	override readonly(value?: boolean | undefined): boolean | this {
		if (value === undefined) {
			return this.attr('readonly') != null;
		}
		this.attr('readonly', value);
		this.query('input').attr('readonly', true);
		return this;
	}

	onPopup(handler: PopupHandler<Select> | null) {
		this[DATA].handler = handler;
		return this;
	}
}

export function select(...className: string[]): Select {
	return new Select().addClass(...className);
}
